package org.ala.tiktools.rpc.netty.handler;

import java.util.List;

import org.ala.tiktools.logs.LoggerFactory;
import org.ala.tiktools.rpc.exception.RpcReadException;
import org.ala.tiktools.rpc.msg.RpcMsg;
import org.ala.tiktools.rpc.msg.RpcMsgHead;
import org.ala.tiktools.rpc.msg.RpcMsgHeadTypeEnums;
import org.slf4j.Logger;

import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.ByteToMessageDecoder;

/**
 * 消息解码器
 *
 * @author ala
 * @date 2025-04-08 09:41
 */
public class RpcMsgDecoder extends ByteToMessageDecoder {


    static Logger log = LoggerFactory.getLogger("rpc", "decoder_encoder");


    /**
     *  上次没读到消息体的头
     */
    protected RpcMsgHead lastHead;


    @SuppressWarnings("rawtypes")
	@Override
    protected void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) throws Exception {
        //  如果剩下的字节数够一个消息头，或头已经取出来了够一个消息体
        while (true) {
            //  如果存在上次没读完的消息头，继续读消息体
            if (lastHead != null) {
                if (!isSufficientBody(lastHead, in)) {break;}
                RpcMsg msg = readBody(lastHead, in);

                out.add(msg);
                lastHead = null;
            } else {
                if (!isSufficientHead(in)) {break;}
                lastHead = readHead(in);
            }
        }
    }


    /**
     *  可读区是否够一个消息头
     */
    protected boolean isSufficientHead(ByteBuf in) {
        return in.readableBytes() >= RpcMsgHead.LENGTH;
    }
    /**
     *  读一个消息头
     */
    protected RpcMsgHead readHead(ByteBuf in) throws RpcReadException {
        try {
            return RpcMsgHead.build()
                    .id(in.readLong())
                    .type(RpcMsgHeadTypeEnums.getInstance(in.readInt()))
                    .len(in.readInt());
        } catch (Exception e) {
            throw new RpcReadException(e);
        }
    }


    /**
     *  可读区是否够一个消息体
     */
    protected boolean isSufficientBody(RpcMsgHead head, ByteBuf in) {
        return in.readableBytes() >= head.getLen();
    }
    /**
     *  读一个消息体
     */
    @SuppressWarnings("rawtypes")
	protected RpcMsg readBody(RpcMsgHead head, ByteBuf in) throws RpcReadException {
        IRpcMsgDecoderEncoder de = IRpcMsgDecoderEncoder.mapper.get(head.getType());
        if (de == null) {
            throw new RpcReadException(String.format("读取消息异常，无法解析消息类型 type:%s", head.getType()));
        }
        RpcMsg msg = null;
        try {
//            log.info("[RpcMsgDecoder decode] 收到消息 head:{}", head);
            msg = de.decode(head, in);
        } catch (Exception e) {
            throw new RpcReadException(e);
        }
        return msg;
    }
}
